home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / aros / exec / allocmem.c < prev    next >
C/C++ Source or Header  |  1996-09-13  |  7KB  |  288 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: allocmem.c,v 1.7 1996/09/13 17:51:22 digulla Exp $
  4.     $Log: allocmem.c,v $
  5.     Revision 1.7  1996/09/13 17:51:22  digulla
  6.     Use IPTR
  7.  
  8.     Revision 1.6  1996/08/23 17:06:56  digulla
  9.     Began work on ressource tracking
  10.  
  11.     Revision 1.5  1996/08/16 14:05:12  digulla
  12.     Added debug output
  13.  
  14.     Revision 1.4  1996/08/13 13:55:57  digulla
  15.     Replaced __AROS_LA by __AROS_LHA
  16.     Replaced some __AROS_LH*I by __AROS_LH*
  17.     Sorted and added includes
  18.  
  19.     Revision 1.3  1996/08/01 17:41:04  digulla
  20.     Added standard header for all files
  21.  
  22.     Desc:
  23.     Lang:
  24. */
  25. #include <exec/alerts.h>
  26. #include <exec/execbase.h>
  27. #include <aros/libcall.h>
  28. #include <aros/rt.h>
  29. #include <machine.h>
  30. #include "memory.h"
  31.  
  32. #include "exec_debug.h"
  33. #ifndef DEBUG_AllocMem
  34. #   define DEBUG_AllocMem 0
  35. #endif
  36. #if DEBUG_AllocMem
  37. #   undef DEBUG
  38. #   define DEBUG 1
  39. #endif
  40. #include <aros/debug.h>
  41.  
  42. /*****************************************************************************
  43.  
  44.     NAME */
  45.     #include <exec/memory.h>
  46.     #include <clib/exec_protos.h>
  47.  
  48.     __AROS_LH2(APTR, AllocMem,
  49.  
  50. /*  SYNOPSIS */
  51.     __AROS_LHA(ULONG, byteSize,     D0),
  52.     __AROS_LHA(ULONG, requirements, D1),
  53.  
  54. /* LOCATION */
  55.     struct ExecBase *, SysBase, 33, Exec)
  56.  
  57. /*  FUNCTION
  58.     Allocate some memory from the sytem memory pool with the given
  59.     requirements.
  60.  
  61.     INPUTS
  62.     byteSize     - Number of bytes you want to get
  63.     requirements - Type of memory
  64.  
  65.     RESULT
  66.     A pointer to the number of bytes you wanted or NULL if the memory
  67.     couldn't be allocated
  68.  
  69.     NOTES
  70.     The memory is aligned to sizeof(struct MemChunk). All requests
  71.     are rounded up to a multiple of that size.
  72.  
  73.     EXAMPLE
  74.     mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  75.  
  76.     BUGS
  77.  
  78.     SEE ALSO
  79.     FreeMem()
  80.  
  81.     INTERNALS
  82.  
  83.     HISTORY
  84.     8-10-95    created by m. fleischer
  85.        16-10-95    increased portability
  86.  
  87. ******************************************************************************/
  88. {
  89.     __AROS_FUNC_INIT
  90.     struct Interrupt *lmh;
  91.     struct MemHandlerData lmhd={ byteSize,requirements,0 };
  92.     APTR res = NULL;
  93. #if ENABLE_RT
  94.     ULONG origSize = byteSize;
  95. #endif
  96.  
  97.     D(bug("Call AllocMem (%d, %08lx)\n", byteSize, requirements));
  98.  
  99.     /* Zero bytes requested? May return everything ;-). */
  100.     if(!byteSize)
  101.     goto end;
  102.  
  103.     /* First round byteSize to a multiple of MEMCHUNK_TOTAL. */
  104.     byteSize=(byteSize+MEMCHUNK_TOTAL-1)&~(MEMCHUNK_TOTAL-1);
  105.  
  106.     /* Protect memory list against other tasks */
  107.     Forbid();
  108.  
  109.     /* Loop over low memory handlers */
  110.     lmh=(struct Interrupt *)SysBase->ex_MemHandlers.mlh_Head;
  111.     for(;;)
  112.     {
  113.     struct MemHeader *mh;
  114.     ULONG lmhr;
  115.  
  116.     /* Loop over MemHeader structures */
  117.     mh=(struct MemHeader *)SysBase->MemList.lh_Head;
  118.     while(mh->mh_Node.ln_Succ!=NULL)
  119.     {
  120.         struct MemChunk *p1,*p2;
  121.  
  122.         /*
  123.         Check for the right requirements and enough free memory.
  124.         The requirements are OK if there's no bit in the
  125.         'attributes' that isn't set in the 'mh->mh_Attributes'.
  126.         MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
  127.         as if they were always set in the memheader.
  128.         */
  129.         if(!(requirements&~(MEMF_CLEAR|MEMF_REVERSE|
  130.                 MEMF_NO_EXPUNGE|mh->mh_Attributes))
  131.            &&mh->mh_Free>=byteSize)
  132.         {
  133.         struct MemChunk *mc=NULL;
  134.  
  135.         /*
  136.             The free memory list is only single linked, i.e. to remove
  137.             elements from the list I need node's predessor. For the
  138.             first element I can use mh->mh_First instead of a real predessor.
  139.         */
  140.         p1=(struct MemChunk *)&mh->mh_First;
  141.         p2=p1->mc_Next;
  142.  
  143.         /* Is there anything in the list? */
  144.         if(p2!=NULL)
  145.         {
  146.             /* Then follow it */
  147.             for(;;)
  148.             {
  149. #if !defined(NO_CONSISTENCY_CHECKS)
  150.             /* Consistency check: Check alignment restrictions */
  151.             if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
  152.                & (MEMCHUNK_TOTAL-1) )
  153.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  154. #endif
  155.             /* Check if the current block is large enough */
  156.             if(p2->mc_Bytes>=byteSize)
  157.             {
  158.                 /* It is. */
  159.                 mc=p1;
  160.                 /* Use this one if MEMF_REVERSE is not set.*/
  161.                 if(!(requirements&MEMF_REVERSE))
  162.                 break;
  163.                 /* Else continue - there may be more to come. */
  164.             }
  165.  
  166.             /* Go to next block */
  167.             p1=p2;
  168.             p2=p1->mc_Next;
  169.  
  170.             /* Check if this was the end */
  171.             if(p2==NULL)
  172.                 break;
  173. #if !defined(NO_CONSISTENCY_CHECKS)
  174.             /*
  175.                 Consistency check:
  176.                 If the end of the last block+1 is bigger or equal to
  177.                 the start of the current block something must be wrong.
  178.             */
  179.             if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
  180.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  181. #endif
  182.             }
  183.             /* Something found? */
  184.             if(mc!=NULL)
  185.             {
  186.             /*
  187.                 Remember: if MEMF_REVERSE is set
  188.                 p1 and p2 are now invalid.
  189.             */
  190.             p1=mc;
  191.             p2=p1->mc_Next;
  192.  
  193.             /* Remove the block from the list and return it. */
  194.             if(p2->mc_Bytes==byteSize)
  195.             {
  196.                 /* Fits exactly. Just relink the list. */
  197.                 p1->mc_Next=p2->mc_Next;
  198.                 mc=p2;
  199.             }else
  200.             {
  201.                 if(requirements&MEMF_REVERSE)
  202.                 {
  203.                 /* Return the last bytes. */
  204.                 p1->mc_Next=p2;
  205.                 mc=(struct MemChunk *)((UBYTE *)p2+byteSize);
  206.                 }else
  207.                 {
  208.                 /* Return the first bytes. */
  209.                 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
  210.                 mc=p2;
  211.                 }
  212.                 p1=p1->mc_Next;
  213.                 p1->mc_Next=p2->mc_Next;
  214.                 p1->mc_Bytes=p2->mc_Bytes-byteSize;
  215.             }
  216.             mh->mh_Free-=byteSize;
  217.  
  218.             /* No need to forbid dispatching any longer. */
  219.             Permit();
  220.             if(requirements&MEMF_CLEAR)
  221.             {
  222.                 /* Clear memory. */
  223.                 ULONG cnt,*p;
  224.  
  225.                 p=(ULONG *)mc;
  226.                 cnt=byteSize/sizeof(ULONG);
  227.  
  228.                 while(cnt--)
  229.                 *p++=0;
  230.             }
  231.             res=mc;
  232.             goto end;
  233.             }
  234.         }
  235.         }
  236.         /* Go to next memory header */
  237.         mh=(struct MemHeader *)mh->mh_Node.ln_Succ;
  238.     }
  239.  
  240.     /* Is it forbidden to call low-memory handlers? */
  241.     if(requirements&MEMF_NO_EXPUNGE)
  242.     {
  243.         Permit();
  244.         goto end;
  245.     }
  246.  
  247.     /* All memory headers done. Check low memory handlers. */
  248.     do
  249.     {
  250.         /* Is there another one? */
  251.         if(lmh->is_Node.ln_Succ==NULL)
  252.         {
  253.         /* No. return 'Not enough memory'. */
  254.         Permit();
  255.         goto end;
  256.         }
  257.         /* Yes. Execute it. */
  258.         lmhr=__AROS_ABS_CALL3(LONG,lmh->is_Code,&lmhd,A0,lmh->is_Data,A1,SysBase,A6);
  259.  
  260.         /* Check returncode. */
  261.         if(lmhr==MEM_TRY_AGAIN)
  262.         {
  263.         /* MemHandler said he did something. Try again. */
  264.         /* Is there any program that depends on this flag??? */
  265.         lmhd.memh_Flags|=MEMHF_RECYCLE;
  266.         break;
  267.         }
  268.         /* Nothing more to expect from this handler. */
  269.         lmh=(struct Interrupt *)lmh->is_Node.ln_Succ;
  270.         lmhd.memh_Flags&=~MEMHF_RECYCLE;
  271.  
  272.     /*
  273.         If this handler did nothing at all there's no need
  274.         to try the allocation. Try the next handler immediately.
  275.     */
  276.     }while(lmhr==MEM_DID_NOTHING);
  277.     }
  278.  
  279. end:
  280. #if ENABLE_RT
  281.     RT_Add (RTT_MEMORY, res, origSize);
  282. #endif
  283.  
  284.     ReturnPtr ("AllocMem", APTR, res);
  285.     __AROS_FUNC_EXIT
  286. } /* AllocMem */
  287.  
  288.